package com.itdct.mto.core.manager;

import com.itdct.mto.core.base.BaseManager;
import com.itdct.mto.core.bo.TableBo;
import com.itdct.mto.core.context.Context;

import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

/**
 * @author Zhouwx
 * @version 1.0
 * @date 2025/7/3 14:13:41
 * @description
 */
@Slf4j
@Component
public class ResultPrintManager extends BaseManager {
    private final static String SPLIT_CHAR = ",";

    @SneakyThrows
    public void writeResult(Context context) {
        log.info("开始打印结果");
        long totalStartTime = context.getTotalStartTime();
        String outputPath = "../result/mto-" + totalStartTime + "/";
        File outputDir = new File(outputPath);
        if (!outputDir.exists()) {
            outputDir.mkdirs();
        }

        outputPath = outputDir.getCanonicalPath() + "/";
        outputOverview(context, outputPath);

        outputCsv(context, outputPath);
        try {
            log.info("结果打印完成，路径为：{}", outputDir.getCanonicalPath());
        } catch (IOException e) {
            log.error("", e);
        }
    }

    private void outputOverview(Context context, String outputPath) {
        String overviewFilePath = outputPath + "overview.txt";
        long totalStartTime = context.getTotalStartTime();
        long totalEndTime = context.getTotalEndTime();

        String startTimeString = DateUtil.format(new Date(totalStartTime), "yyyy-MM-dd HH:mm:ss");
        String endTimeString = DateUtil.format(new Date(totalEndTime), "yyyy-MM-dd HH:mm:ss");

        long totalTime = totalEndTime - totalStartTime;
        int totalTableCount = context.getTableBos().size();
        int failTableCount = context.getFailTableNames().size();

        long analyseTime = context.getAnalyseEndTime() - context.getAnalyseStartTime();
        long convertTime = context.getConvertEndTime() - context.getConvertStartTime();
        long transferTime = context.getTransferEndTime() - context.getTransferStartTime();

        String content = "开始时间：" + startTimeString + "\n" +
                "结束时间：" + endTimeString + "\n" +
                "总耗时：" + getSecondTimeString(totalTime) + "\n" +
                "总转换表数：" + context.getTableBos().size() + "\n" +
                "成功转换表数：" + (totalTableCount - failTableCount) + "\n" +
                "失败转换表数：" + failTableCount + "\n" +
                "分析表信息耗时：" + getSecondTimeString(analyseTime) + "\n" +
                "转换表耗时：" + getSecondTimeString(convertTime) + "\n" +
                "传输数据耗时：" + getSecondTimeString(transferTime) + "\n";
        content += "\n失败的表表名：\n";
        for (String failTableName : context.getFailTableNames()) {
            content += "\t" + failTableName + "\n";
        }
        FileUtil.writeString(content, overviewFilePath, Charset.defaultCharset());
    }

    private void outputCsv(Context context, String outputPath) {
        String outputCsvFilePath = outputPath + "table-result.csv";
        File file = new File(outputCsvFilePath);
        try {
            file.createNewFile();
        } catch (Exception e) {
            log.error("创建文件失败", e);
        }

        ArrayList<String> titleList = new ArrayList<>();
        titleList.add("表名");
        titleList.add("表结构分析是否成功");
        titleList.add("表结构转换是否成功");
        titleList.add("外键约束转换是否成功");
        titleList.add("数据传输是否成功");
        titleList.add("数据总量");
        titleList.add("数据传输总耗时");
        titleList.add("报错信息");
        String title = String.join(SPLIT_CHAR, titleList);

        FileUtil.writeString(title + "\n", outputCsvFilePath, Charset.defaultCharset());

        String errorPath = outputPath + "error/";
        File errorDir = new File(errorPath);
        if (!errorDir.exists()) {
            errorDir.mkdirs();
        }

        List<TableBo> tableBos = context.getTableBos();
        for (TableBo tableBo : tableBos) {
            ArrayList<String> lineList = new ArrayList<>();
            String tableName = tableBo.getTableName();
            lineList.add(tableName);
            lineList.add(tableBo.isAnalyseSuccess() ? "√" : "x");
            lineList.add(tableBo.isConvertSuccess() ? "√" : "x");
            lineList.add(tableBo.isForeignKeySuccess() ? "√" : "x");
            if (context.getTransferStartTime() > 0L) {
                // INFO: Zhouwx: 2025/7/3 存在传输数据的情况
                lineList.add(tableBo.isTransferSuccess() ? "√" : "x");
                lineList.add(tableBo.getTotalCount() + "");
                long transferStartTime = tableBo.getTransferStartTime();
                long transferEndTime = tableBo.getTransferEndTime();
                long totalMs = transferEndTime - transferStartTime;
                String totalTransferTime = getSecondTimeString(totalMs);
                lineList.add(totalTransferTime);
            } else {
                lineList.add("-");
                lineList.add("-");
                lineList.add("-");
            }
            Exception exception = tableBo.getException();
            if (exception != null) {
                lineList.add(exception.getMessage());

                writeToErrorFile(errorPath, tableName, getFullExceptionTrace(exception));
            } else {
                lineList.add("-");
            }

            String lineString = String.join(SPLIT_CHAR, lineList) + "\n";
            FileUtil.appendString(lineString, outputCsvFilePath, Charset.defaultCharset());

        }
    }

    private static String getSecondTimeString(long totalMs) {
        if (totalMs == 0L) {
            return "0秒";
        }
        return new BigDecimal(totalMs).divide(new BigDecimal(1000), 3, RoundingMode.HALF_UP) + "秒";
    }

    private void writeToErrorFile(String errorPath, String tableName, String fullExceptionTrace) {
        File errorFile = new File(errorPath + tableName + ".txt");
        try {
            errorFile.createNewFile();
        } catch (Exception e) {
            log.error("创建文件失败", e);
        }
        FileUtil.writeString(fullExceptionTrace, errorFile, Charset.defaultCharset());
    }

    public static String getFullExceptionTrace(Exception exception) {
        if (exception == null) {
            return "";
        }
        return exception.getMessage();
    }

}
